﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ttlang.compiler;

namespace ttlang.semantic
{
    public class TTArg
    {
        public TTType argtype = null;
        public string name = "";
        public bool optional = false;
        public node.Node_Expr initvalue;//null 表示无初值
        public src.AstNode notParseType;
        public src.AstNode notParseInitValue;
        public TTArg(TTType _type, string _name)
        {
            this.argtype = _type;
            this.name = _name;
        }
        private TTArg()
        {

        }
        public static TTArg Create(src.AstNode innode)
        {
            var _arg = new TTArg();
            _arg.name = innode.children[0].text;
            _arg.notParseType = innode.children[2];
            if(innode.children.Count>4)
            _arg.notParseInitValue = innode.children[4];
            return _arg;

        }
    }
    public class TTMethod : IMember
    {

        //public Module module;
        //public string _namespace;
        //public IContainer? container;
        //public string name = "";
        public TTArg[] args;
        public TTType tttype
        {
            get
            {
                return ReturnType;
            }
        }
        public TTType ReturnType;
        public node.Node_CodeBlock body;
        public string[] modifers;//将来改成枚举
        public node.Node_Expr_Call[] attributes;//
        public TTMethod(IContainer _container, string _id, TTArg[] _args, TTType _returntype)
        {
            //this.module = _module;
            //this._namespace = __namespace;
            this.container = _container;
            this.name = _id;
            if (_args != null)
                this.args = _args;
            else
                this.args = new TTArg[0];

            this.ReturnType = _returntype;
        }
        public src.AstNode notParseNodeBody;
        public src.AstNode notParseNodeReturnType;
        public bool nobody = false;
        public bool IsNoBody()
        {
            return nobody;
        }
        public string name
        {
            get;
            private set;
        }

        public IContainer container
        {
            get;
            private set;
        }
        public string fullname
        {
            get
            {
                if (container != null)
                {
                    return container.fullname + "." + name;
                }
                else
                {
                    return name;
                }
            }
        }
        public MEMBERTYPE type => MEMBERTYPE.METHOD;

        public static TTMethod Create(CompilerContext context, IContainer _container, src.AstNode innode)
        {
            string name = "";
            int childstart = 0;

            //0 id
            //1 {
            //end }
            List<string> modifers = new List<string>();
            List<node.Node_Expr_Call> attrs = new List<node.Node_Expr_Call>();
        
            for (var i = 0; i < innode.children.Count; i++)
            {
                if(innode.children[i].type=="modifiers")
                {
                    //处理修饰器
                    var mod = innode.children[i];
                    for (var j =0;j<mod.children.Count;j++)
                    {
                        if(mod.children[j].text=="@")
                        {
                            var next = mod.children[j + 1];
                            compiler.compiler_expr.ParseNode_Expr_Call(context, next, out node.Node_Expr_Call  attr);
                            attrs.Add(attr);
                            j++;
                        }
                        else
                        {
                            modifers.Add(mod.children[j].text);
                        }
                    }
                    
                }
                if (innode.children[i].type == "ID")
                {
                    name = innode.children[i].text;
                    childstart = i + 2; //skip '('

                    //args
                    break;
                }
            }
            //find args
            List<src.AstNode> args = new List<src.AstNode>();
            for (var i = childstart; i < innode.children.Count; i++)
            {
                if (innode.children[i].type == "arg_def")
                {
                    args.Add(innode.children[i]);
                }
                if (innode.children[i].text == ")")
                {
                    childstart = i + 1;
                    break;
                }
            }
            TTArg[] ttargs = new TTArg[args.Count];
            for (var i = 0; i < args.Count; i++)
            {
                ttargs[i] = TTArg.Create(args[i]);
            }
            src.AstNode returntype = null;
            //return value;
            if (innode.children[childstart].text == ":")
            {

                returntype = innode.children[childstart + 1];
                childstart += 2;
            }

            int bodyindex = -1;
            //body
            for (var i = childstart; i < innode.children.Count; i++)
            {
                if (innode.children[i].type == "code_block")
                {
                    bodyindex = i;
                    break;
                }
                else if (innode.children[childstart].type == ";")//nobody
                {
                    bodyindex = -2;
                    break;
                }
            }
            if (bodyindex == -2)
                throw new Exception("unknown error.");

            semantic.TTMethod _method = new semantic.TTMethod(_container, name, ttargs, null);
            _method.modifers = modifers.ToArray();
            _method.attributes = attrs.ToArray();
            //第一遍不需要深入处理
            _method.notParseNodeBody = bodyindex >= 0 ? innode.children[bodyindex] : null;
            _method.notParseNodeReturnType = returntype;
            if (returntype == null)
            {
                SystemModule.ttlangCore.FindType("void", out _method.ReturnType);
            }
            return _method;
        }
        public bool Ready()
        {
            if (this.notParseNodeReturnType != null) return false;
            if (this.notParseNodeBody != null && nobody == false)
                return false;
            return true;
        }

    }
}